home *** CD-ROM | disk | FTP | other *** search
/ Deutsche Edition 1 / Deutsche Edition 1.iso / amok / amok_lha / amok59.lha / AmokEd_V1.02b / txt / EdLowLevel.mod < prev    next >
Text File  |  1993-08-15  |  15KB  |  576 lines

  1. (*************************************************************************
  2.  
  3. :Program.    EdLowLevel.mod
  4. :Contents.   Lowlevel-Support-Routines for AmokEd
  5. :Author.     Hartmut Goebel
  6. :Language.   Oberon
  7. :Translator. AmigaOberon V2.00
  8. :Imports.    Printf (Volker Rudolph), SupLib (Hartmut Goebel)
  9. :History.    V0.1, 03 Dec 1990 Hartmut Goebel
  10. :History.    V1.0, 14 Apr 1991 Hartmut Goebel [hG]
  11. :History.    V1.1, 22 Apr 1991 [hG] New/FreeLine über Exec.Alloc/FreeMem
  12. :History.    V1.2, 28 Apr 1991 [hG] +TextInit -NewEdit
  13. :History.    V1.2b 29 Apr 1991 [hG] ^WindowTitle
  14. :History.    V1.2c 29 May 1991 [hG] changed check of Dos-Version
  15. :History.    V1.2d 19 Jun 1991 [hG] +neue FreeLines() (Volker Rudolph)
  16. :History.    V1.2e 12 Oct 1991 [hG] +NCStrCmp
  17. :History.    V1.2f 18 Oct 1991 [hG] +DeletePort
  18. :Date.       19 Oct 1991 03:02:00
  19.  
  20. *************************************************************************)
  21. (* $Debug- *)
  22. MODULE EdLowLevel;
  23.  
  24. IMPORT
  25.   Printf, (*io,*)
  26.   arg: Arguments,
  27.   con: Console,
  28.   d  : Dos,
  29.   e  : Exec,
  30.   eAD: EdApplDefs,
  31.   es : ExecSupport,
  32.   edE: EdErrors,
  33.   edG: EdGlobalVars,
  34.   g  : Graphics,
  35.   I  : Intuition,
  36.   ie : InputEvent,
  37.   lst: EdLists,
  38.   ol : OberonLib,
  39.   sl : SupLib,
  40.   str: Strings,
  41.   s  : SYSTEM;
  42.  
  43. VAR
  44.   TitleText: edG.StringPtr; (* sicherstellen, daß Titel erhalten bleibt *)
  45.  
  46. CONST
  47.   CTRLC = LONGSET{d.ctrlC};
  48.  
  49. PROCEDURE MoveToCursor*;
  50. BEGIN
  51.   g.Move(edG.RPort,edG.XTBase+(edG.Text.pos-edG.Text.topPos)*edG.XSize,
  52.          edG.YTBase+(SHORT(edG.Text.line-edG.Text.topLine))*edG.YSize);
  53. END MoveToCursor;
  54.  
  55. (*-------------------------------------------------------------------------*)
  56.  
  57. PROCEDURE Length(str{8}: edG.StringPtr): INTEGER;
  58. VAR
  59.   p: edG.StringPtr;
  60. BEGIN
  61.   WHILE str[0] # 0X DO
  62.     INC(str); END;
  63.   RETURN SHORT(s.VAL(LONGINT,str)-s.VAL(LONGINT,p));
  64. END Length;
  65.  
  66.  
  67. PROCEDURE CopyString*(from: edG.StringPtr): edG.StringPtr;
  68. VAR
  69.   len: INTEGER;
  70.   new: edG.StringPtr;
  71. BEGIN
  72.   IF from=NIL THEN RETURN NIL; END;
  73.   len := str.Length(from^)+1;
  74.   ol.New(new,len);
  75.   IF new=NIL THEN
  76.     INCL(edG.Status,edG.memoryFail); edG.Rc := edE.cmdSevere;
  77.     RETURN NIL;
  78.   END;
  79.   e.CopyMem(from^,new^,len);
  80.   RETURN new;
  81. END CopyString;
  82.  
  83.  
  84. PROCEDURE FreeString*(string: edG.StringPtr);
  85. BEGIN
  86.   DISPOSE(string);
  87. END FreeString;
  88.  
  89.  
  90. (* $Debug= *)
  91. PROCEDURE NCStrCmp*(str1{8}, str2{9}: edG.StringPtr): INTEGER;
  92. BEGIN
  93.   WHILE CAP(str1[0]) = CAP(str2[0]) DO
  94.     IF str1[0] = 0X THEN
  95.       RETURN 0; END;
  96.     INC(str1); INC(str2);
  97.   END;
  98.   RETURN ORD(str1[0])-ORD(str2[0]);
  99. END NCStrCmp;
  100. (* $Debug- *)
  101.  
  102. (*-------------------------------------------------------------------------*)
  103.  
  104. PROCEDURE IsAscii*(ch{0}: CHAR): BOOLEAN;
  105. BEGIN
  106.  CASE ch OF
  107.    "0".."9","A".."Z","a".."z","_",CHR(192)..CHR(255): RETURN TRUE;
  108.  ELSE
  109.    RETURN FALSE;
  110.  END;
  111. END IsAscii;
  112.  
  113.  
  114. PROCEDURE WordLen*(str{8}: edG.StringPtr): INTEGER;
  115. VAR
  116.   i: INTEGER;
  117. BEGIN
  118.   i := 0;
  119.   WHILE (str[0] # 0X) AND (str[0] # " ") DO
  120.     INC(i);
  121.     INC(str);
  122.   END;
  123.   RETURN i;
  124. END WordLen;
  125.  
  126.  
  127. PROCEDURE LastNoSpace*(string{8}: edG.StringPtr): INTEGER;
  128. VAR
  129.   i: INTEGER;
  130. BEGIN
  131.   i := str.Length(string^);
  132.   REPEAT
  133.     DEC(i);
  134.   UNTIL (i = 0) OR (string[i] # " ");
  135.   RETURN i;
  136. END LastNoSpace;
  137.  
  138.  
  139. PROCEDURE FirstNoSpace*(string{8}: edG.StringPtr): INTEGER;
  140. VAR
  141.   i: INTEGER;
  142. BEGIN
  143.   i := 0;
  144.   WHILE string[i] = " " DO
  145.     INC(i);
  146.   END;
  147.   IF string[i] = "\o" THEN i := 0; END;
  148.   RETURN i;
  149. END FirstNoSpace;
  150.  
  151.  
  152. PROCEDURE StripEndSpaces*;
  153. VAR
  154.   len: INTEGER;
  155. BEGIN
  156.   len := str.Length(edG.LineBuffer);
  157.   REPEAT
  158.     DEC(len);
  159.   UNTIL (len < 0) OR (edG.LineBuffer[len] # 20X);
  160.   INC(len);
  161.   edG.LineBuffer[len] := 0X;
  162.   edG.LineBufferLen := len;
  163. END StripEndSpaces;
  164.  
  165.  
  166. PROCEDURE FillUpSpaces*;
  167. VAR
  168.   j, i: INTEGER;
  169. BEGIN
  170.   i := edG.Text.pos;
  171.   j := edG.LineBufferLen;
  172.   WHILE i > j DO
  173.     edG.LineBuffer[j] := 20X;
  174.     INC(j);
  175.   END;
  176.   edG.LineBuffer[j] := 0X;
  177.   edG.LineBufferLen := j;
  178. END FillUpSpaces;
  179.  
  180. (*-------------------------------------------------------------------------*)
  181.  
  182. PROCEDURE FreeLines*(VAR List: lst.List; Start, End: edG.LinePtr);
  183. VAR
  184.   This: edG.LinePtr;
  185.   TempList: lst.Mark;
  186.   memStart, memEnd:e.ADDRESS;
  187. BEGIN
  188.   lst.SetMark(TempList,Start,End);
  189.   lst.RemoveMark(List,TempList);
  190.   TempList.tail.next := NIL;
  191.   This := TempList.head(edG.Line);
  192.   memStart := This;
  193.   memEnd := This;
  194.   REPEAT
  195.     TempList.head := This.next; (* gar nicht erst Remove, gleich freigeben *)
  196.     WITH This:edG.Line DO
  197.  
  198.       IF memEnd = This THEN
  199.         INC(memEnd,edG.LineAllocSize);
  200.       ELSE
  201.         e.FreeMem(memStart,memEnd-memStart);
  202.         memStart := This;
  203.         memEnd := s.VAL(LONGINT,This)+edG.LineAllocSize;
  204.       END; (* IF *)
  205.  
  206.       IF memEnd = This.string THEN
  207.         INC(memEnd,This.len);
  208.       ELSE
  209.         e.FreeMem(memStart,memEnd-memStart);
  210.         memStart := This.string;
  211.         memEnd := s.VAL(LONGINT,This.string)+This.len;
  212.       END; (* IF *)
  213.  
  214.     END; (* WITH *)
  215.     This := TempList.head;
  216.   UNTIL This = NIL;
  217.  
  218.   e.FreeMem(memStart,memEnd-memStart);
  219.  
  220. END FreeLines;
  221.  
  222.  
  223. PROCEDURE NewLine*(VAR line: edG.LinePtr; len: INTEGER);
  224. BEGIN
  225.   line := e.AllocMem(len+edG.LineAllocSize,LONGSET{});
  226.   IF line # NIL THEN
  227.     (* $TypeChk- *)
  228.     WITH line:edG.Line DO
  229.       s.INIT(line);
  230.       line.string := s.VAL(LONGINT,line)+edG.LineAllocSize;
  231.       line.string^ := "";
  232.       line.len := len;
  233.     END; (* WITH *)
  234.     (* $TypeChk= *)
  235.     RETURN;
  236.   END;
  237.   INCL(edG.Status,edG.memoryFail);
  238. END NewLine;
  239.  
  240.  
  241. PROCEDURE CreateLineCopy*(from: edG.LinePtr): edG.LinePtr;
  242. VAR
  243.   NewOne: edG.LinePtr;
  244. BEGIN
  245.   NewOne := e.AllocMem(from(edG.Line).len+edG.LineAllocSize,LONGSET{});
  246.   IF NewOne#NIL THEN
  247.     (* $TypeChk- *)
  248.     WITH NewOne:edG.Line DO
  249.       s.INIT(NewOne);
  250.       NewOne.len := from(edG.Line).len;
  251.       NewOne.string := s.VAL(LONGINT,NewOne)+edG.LineAllocSize;
  252.       e.CopyMemQuick(from(edG.Line).string^,NewOne.string^,NewOne.len);
  253.     END; (* WITH *)
  254.     (* $TypeChk= *)
  255.     RETURN NewOne;
  256.   END;
  257.   INCL(edG.Status,edG.memoryFail);
  258.   RETURN NIL;
  259. END CreateLineCopy;
  260.  
  261. (*-------------------------------------------------------------------------*)
  262.  
  263. PROCEDURE StrToInt*(string: edG.StringPtr; VAR int: LONGINT): BOOLEAN;
  264. VAR
  265.   n: INTEGER;
  266.   neg: BOOLEAN;
  267. BEGIN
  268.   int := 0; neg := FALSE;
  269.   WHILE string[0]=20X DO INC(string) END;
  270.   CASE string[0] OF "-","+": neg := string[0]="-"; INC(string) ELSE END;
  271.   LOOP
  272.     CASE string[0] OF "0".."9":
  273.       n := ORD(string[0])-ORD("0");
  274.       IF int>(MAX(LONGINT)-n) DIV 10 THEN RETURN FALSE
  275.                                      ELSE int := 10*int + n END |
  276.     ELSE
  277.       IF neg THEN int := -int END;
  278.       WHILE string[0]=20X DO INC(string) END;
  279.       RETURN string[0]=0X
  280.     END;
  281.     INC(string);
  282.   END;
  283. END StrToInt;
  284.  
  285. (*-------------------------------------------------------------------------*)
  286.  
  287. PROCEDURE KillMarks;
  288. VAR
  289.   i, j: INTEGER;
  290. BEGIN
  291.   i := edG.NumPingPongs;
  292.   REPEAT (* remove PingPong Marks *)
  293.     DEC(i);
  294.     IF edG.PingPong[i].txt = edG.Text THEN edG.PingPong[i].txt := NIL; END;
  295.   UNTIL i = 0;
  296.   j := 0; (*i:=0*)
  297.   REPEAT (* remove Block Marks *)
  298.     IF edG.BStack[i].Owner # edG.Text THEN
  299.       edG.BStack[j].Owner := edG.BStack[i].Owner;
  300.       INC(j);
  301.     END;
  302.     INC(i);
  303.   UNTIL i >= edG.BStackCurrDepth; (* >= wg. BStackCurrDepth = 0 *)
  304.   edG.BStackCurrDepth := j;
  305.   IF edG.Block.Owner = edG.Text THEN (* unblock *)
  306.     edG.Block.SNum := -1; edG.Block.ENum := -1; END;
  307. END KillMarks;
  308.  
  309.  
  310. PROCEDURE TextInit*(VAR nw: I.NewWindow): edG.TextHeaderPtr;
  311. VAR
  312.   txt: edG.TextHeaderPtr;
  313. BEGIN
  314.   (* es ist unnötig, Felder mit NIL oder 0 zu initialisieren,
  315.    * da ol.New mit {e.memClear} alloziert
  316.    *)
  317.   ol.New(txt,s.SIZE(edG.TextHeader));
  318.   IF txt # NIL THEN (* $TypeChk- *)
  319.     s.INIT(txt); (* $TypeChk= *)
  320.     txt.name := edG.unNamed;
  321.     txt.propGadget := edG.Gadget1;
  322.     txt.propGadget.specialInfo := s.ADR(txt.propInfo);
  323.     txt.propInfo := edG.Gadget1SInfo;
  324.     nw.firstGadget := s.ADR(txt.propGadget);
  325.     txt.window := sl.OpenPortWindow(nw,edG.MainPort);
  326.       IF txt.window = NIL THEN
  327.         DISPOSE(txt); RETURN NIL;
  328.       END;
  329.     I.SetWindowTitles(txt.window,s.ADR(edG.Copyright),-1);
  330.     txt.numberOfLines := 1;
  331.     NewLine(txt.actLinePtr,edG.ChunkSize);
  332.     lst.AddHead(txt.lineList,txt.actLinePtr);
  333.     txt.topLinePtr := txt.actLinePtr;
  334.     txt.iconTop := 12;
  335.     txt.margin := 69;
  336.     lst.AddTail(edG.EditList,txt);
  337.     IF edG.Text#NIL THEN (* nicht erster Text *)
  338.       txt.dirLock := d.DupLock(edG.Text.dirLock);
  339.       txt.status := edG.Text.status - LONGSET{edG.quit,edG.macroWithQuit,
  340.                                               edG.keepTitle,edG.modified};
  341.       txt.tabStop := edG.Text.tabStop;
  342.       IF edG.Text.font#NIL THEN
  343.         txt.font := edG.Text.font;
  344.         INC(txt.font.accessors);
  345.         g.SetFont(txt.window.rPort,txt.font);
  346.       END;
  347.     ELSE
  348.       edG.Text := txt;
  349.       txt.dirLock := d.DupLock(arg.Me.currentDir);
  350.       txt.tabStop := 4;
  351.       txt.status := LONGSET{edG.insertMode};
  352.     END;
  353.   END;
  354.   RETURN txt;
  355. END TextInit;
  356.  
  357.  
  358. PROCEDURE EndEdit*;
  359. BEGIN
  360.   IF edG.Text.lineList.head#NIL THEN
  361.     FreeLines(edG.Text.lineList,edG.Text.lineList.head(edG.Line),
  362.               edG.Text.lineList.tail(edG.Line));
  363.   END;
  364.   IF edG.Text.font#NIL THEN
  365.     g.SetFont(edG.RPort,edG.Text.window.wScreen.rastPort.font);
  366.     g.CloseFont(edG.Text.font);
  367.   END;
  368.   IF edG.Text.window # NIL THEN sl.CloseWindowSafely(edG.Text.window); END;
  369.   KillMarks;
  370.   d.UnLock(edG.Text.dirLock);
  371.   lst.Remove(edG.EditList,edG.Text);
  372.   DISPOSE(edG.Text);
  373.   edG.Text := edG.EditList.head(edG.TextHeader);
  374. END EndEdit;
  375.  
  376. (*-------------------------------------------------------------------------*)
  377.  
  378. PROCEDURE Title*(winText{8}: ARRAY OF CHAR); (* $CopyArrays- *)
  379. BEGIN
  380.   I.SetWindowTitles(edG.Text.window,s.ADR(winText),-1);
  381. END Title;
  382.  
  383.  
  384. PROCEDURE doTitle*;
  385. BEGIN
  386.   DISPOSE(TitleText);
  387.   TitleText := CopyString(edG.Arg[0]);
  388.   I.SetWindowTitles(edG.Text.window,TitleText,-1);
  389.   INCL(edG.Text.status,edG.keepTitle); edG.Rc := edE.cmdValid2;
  390. END doTitle;
  391.  
  392. (*
  393.  * zeigt edG.Text.actLineNum, edG.Text.numberOfLines, edG.Text.pos,
  394.  * edG.Text.Name und ggf. Statusmeldungen an.
  395. *)
  396. PROCEDURE WindowTitle*;
  397. CONST
  398.  Modified = "(modified)\o";
  399. VAR
  400.   Win: I.WindowPtr;
  401.   len, maxlen: INTEGER;
  402.   font, oldfont: g.TextFontPtr;
  403.   mod: ARRAY 11 OF CHAR;
  404. BEGIN
  405.   IF edG.memoryFail IN edG.Status THEN
  406.     I.SetWindowTitles(edG.Text.window,s.ADR(edG.NoMemory),-1);
  407.     RETURN;
  408.   END;
  409.   IF (edG.Rc > edE.TitleThreshhold) THEN RETURN; END;
  410.  
  411.   IF edG.modified IN edG.Text.status THEN
  412.     e.CopyMem(Modified,mod,11);
  413.   ELSE
  414.     e.CopyMem(edG.Spaces,mod,11);
  415.   END;
  416.   Printf.SPrintf5(edG.Text.wTitle,"%3ld/%-3ld %3ld %s %s  ",
  417.                   edG.Text.line+1,edG.Text.numberOfLines,edG.Text.pos+1,
  418.                   s.ADR(edG.Text.name),s.ADR(mod));
  419.   Win := edG.Text.window;
  420.   oldfont := Win.rPort.font;
  421.   g.SetFont(Win.rPort,Win.wScreen.rastPort.font);
  422.  
  423.   IF edG.kick20 IN edG.Status THEN
  424.     I.SetWindowTitles(Win,s.ADR(edG.Text.wTitle),-1);
  425.   ELSE
  426.     len := str.Length(edG.Text.wTitle);
  427.     Win.title := s.ADR(edG.Text.wTitle);
  428.     font := Win.rPort.font;
  429.     maxlen := (Win.width-90) DIV font.xSize;
  430.     IF maxlen < 0 THEN maxlen := 0; END;
  431.     IF len > maxlen THEN len := maxlen; END;
  432.     g.SetAPen(Win.rPort,0); g.SetBPen(Win.rPort,1);
  433.     g.Move(Win.rPort,30,font.baseline+1);
  434.     g.Text(Win.rPort,edG.Text.wTitle,len);      (*  No flash  *)
  435.     g.SetAPen(Win.rPort,1); g.SetBPen(Win.rPort,0);
  436.     IF maxlen - len > 0 THEN
  437.       g.RectFill(Win.rPort,Win.rPort.x,1,Win.width-54,font.ySize+1);
  438.     END;
  439.   END;
  440.   g.SetFont(Win.rPort,oldfont);
  441. END WindowTitle;
  442.  
  443. (*-------------------------------------------------------------------------*)
  444. (*
  445.  *  Check break by scanning pending messages in the I stream for a ^C.
  446.  *  msgCheck forces a check, else the check is only made if the signal is
  447.  *  set in the I stream (the signal is reset).
  448.  *)
  449. (* $Debug= *)
  450. PROCEDURE BreakCheck*(): BOOLEAN;
  451. VAR
  452.   im: I.IntuiMessagePtr;
  453.  
  454.   class: LONGSET;
  455.   qual: SET;
  456.   code: INTEGER;
  457.  
  458. BEGIN
  459.   IF (edG.msgCheck IN edG.Status)
  460.   OR (edG.MainPort.sigBit IN e.SetSignal(LONGSET{},LONGSET{})) THEN
  461.     EXCL(edG.Status,edG.msgCheck);
  462.     s.SETREG(0,e.SetSignal(LONGSET{},
  463.                            LONGSET{edG.MainPort.sigBit})); (* Löschen *)
  464.     e.Forbid();
  465.     im := edG.MainPort.msgList.head;
  466.     WHILE im.execMessage.node.succ # NIL DO
  467.  
  468.       class := im.class; qual := im.qualifier-{ie.capsLock,8..15};
  469.       code := im.code;
  470.  
  471.       IF (im.idcmpWindow = edG.Text.window)
  472.       AND (im.class = LONGSET{I.rawKey}) (* is IDCMPFlag, not ie.Class *)
  473.       AND ({ie.control} = im.qualifier-{ie.capsLock,8..15})
  474.           (* only check Qualifier-Keys (lower 8 Bits) *)
  475.       AND (im.code = s.VAL(SHORTINT,edG.CtrlC)) THEN
  476.         e.Permit();
  477.         (*
  478.         io.WriteInt(s.VAL(LONGINT,class),5);
  479.         io.WriteInt(s.VAL(INTEGER,qual),5);
  480.         io.WriteInt(s.VAL(INTEGER,code),5);io.WriteLn;
  481.         io.Write("+");
  482.         *)
  483.         s.SETREG(0,e.SetSignal(CTRLC,CTRLC)); (* setzen *)
  484.         RETURN TRUE;
  485.       END;
  486.       im := im.execMessage.node.succ;
  487.     END;
  488.     e.Permit();
  489.     (*
  490.     io.WriteInt(s.VAL(LONGINT,class),5);
  491.     io.WriteInt(s.VAL(INTEGER,qual),5);
  492.     io.WriteInt(s.VAL(INTEGER,code),5);io.WriteLn;
  493.     *)
  494.   END;
  495.   (*io.Write("-");*)
  496.   RETURN FALSE;
  497. END BreakCheck;
  498. (* $Debug- *)
  499.  
  500. PROCEDURE BreakReset*;
  501. BEGIN;
  502.   s.SETREG(0,e.SetSignal(LONGSET{},CTRLC));
  503. END BreakReset;
  504.  
  505. (*-------------------------------------------------------------------------*)
  506.  
  507. (* Sucht <txt>, zu dem <win> gehört *)
  508.  
  509. PROCEDURE FindEdit*(win{8}: I.WindowPtr): edG.TextHeaderPtr;
  510. VAR
  511.   txt: edG.TextHeaderPtr;
  512. BEGIN
  513.   IF win = NIL THEN RETURN NIL; END;
  514.   txt := edG.EditList.head(edG.TextHeader);
  515.   WHILE txt # NIL DO
  516.     IF txt.window = win THEN RETURN txt; END;
  517.     txt := txt.node.next(edG.TextHeader);
  518.   END;
  519.   RETURN NIL;
  520. END FindEdit;
  521.  
  522. (*-------------------------------------------------------------------------*)
  523.  
  524. PROCEDURE DeletePort*(port: e.MsgPortPtr);
  525. VAR
  526.   n, s: e.MessagePtr;
  527. BEGIN
  528.   e.Forbid();
  529.   n := port.msgList.head;
  530.   WHILE n.node.succ # NIL DO
  531.     s := n.node.succ;
  532.     IF n.replyPort # port THEN (* Message does not belong to us *)
  533.       e.Remove(n);
  534.       e.ReplyMsg(n);
  535.     END;
  536.     n := s;
  537.   END;
  538.   e.Permit;
  539.   es.DeletePort(port);
  540. END DeletePort;
  541.  
  542.  
  543. (*-------------------------------------------------------------------------*)
  544.  
  545. BEGIN
  546.   (*
  547.   edG.Text := NIL;
  548.   lst.Init(edG.EditList);
  549.   edG.LineBuffer := ""; edG.LineBufferLen := 0;
  550.   *)
  551.  
  552.   edG.MainPort := es.CreatePort("",0);
  553.     IF edG.MainPort = NIL THEN HALT(20); END;
  554.   edG.MainReq := es.CreateExtIO(edG.MainPort,s.SIZE(e.IOStdReq));
  555.     IF edG.MainReq = NIL THEN HALT(20); END;
  556.   s.SETREG(0,e.OpenDevice(con.consoleName,-1,edG.MainReq,LONGSET{}));
  557.   con.base := edG.MainReq.device;
  558.  
  559.   IF d.dos.lib.version>=36 THEN INCL(edG.Status,edG.kick20);
  560.   ELSE EXCL(edG.Status,edG.kick20);
  561.   END;
  562.  
  563. CLOSE
  564.   WHILE edG.EditList.head#NIL DO  (* falls noch was offen ist *)
  565.     EndEdit; END;
  566.   IF edG.DelLinePtr # NIL THEN
  567.     e.FreeMem(edG.DelLinePtr(edG.Line).string,edG.DelLinePtr(edG.Line).len);
  568.     e.FreeMem(edG.DelLinePtr,edG.LineAllocSize);
  569.   END;
  570.  
  571.   IF con.base # NIL THEN e.CloseDevice(edG.MainReq); END;
  572.   IF edG.MainReq # NIL THEN es.DeleteExtIO(edG.MainReq); END;
  573.   IF edG.MainPort # NIL THEN es.DeletePort(edG.MainPort); END;
  574. END EdLowLevel.
  575.  
  576.